package cn.juque.jdfsystem.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.HMac;
import cn.juque.common.base.PageInfo;
import cn.juque.common.constants.MessageEnum;
import cn.juque.common.exception.AppException;
import cn.juque.common.utils.FastJsonUtil;
import cn.juque.jdfsystem.cache.ConfigInfoCache;
import cn.juque.jdfsystem.entity.UserInfo;
import cn.juque.jdfsystem.enums.ConfigCodeEnum;
import cn.juque.jdfsystem.enums.JdfSystemMsgEnum;
import cn.juque.jdfsystem.service.IUserInfoService;
import cn.juque.lucenecandy.core.base.CountQueryWrapperBuilder;
import cn.juque.lucenecandy.core.base.DeleteByIdsWrapperBuilder;
import cn.juque.lucenecandy.core.base.IdQueryWrapperBuilder;
import cn.juque.lucenecandy.core.base.QueryWrapperBuilder;
import cn.juque.lucenecandy.core.constants.StrConstant;
import cn.juque.lucenecandy.core.enums.MatchTypeEnum;
import cn.juque.lucenecandy.helper.IndexHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.search.BooleanClause;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author JUQUE
 * @version 1.0.0
 * <ul>
 *  <li>simple-generator</li>
 *  <li>用户信息</li>
 * </ul>
 * @date 2023-03-15 17:18:21
 **/
@Slf4j
@Service("userInfoService")
public class UserInfoServiceImpl implements IUserInfoService {

    @Resource
    private IndexHelper indexHelper;

    @Resource
    private ConfigInfoCache configInfoCache;

    /**
     * 分页查询
     *
     * @param pageInfo pageInfo
     * @param userInfo userInfo
     * @return DataGrid
     */
    @Override
    public List<UserInfo> listInfoWithPage(PageInfo pageInfo, UserInfo userInfo) {
        QueryWrapperBuilder<UserInfo> queryWrapperBuilder = this.buildQuery(userInfo);
        queryWrapperBuilder.pageInfo(pageInfo);
        return this.indexHelper.searchByPage(queryWrapperBuilder.build());
    }

    /**
     * 登录
     *
     * @param loginName 登录名
     * @param password  密码
     * @return UserInfo
     */
    @Override
    public UserInfo login(String loginName, String password) {
        Assert.notEmpty(loginName);
        Assert.notEmpty(password);
        QueryWrapperBuilder<UserInfo> queryWrapperBuilder = new QueryWrapperBuilder<>(UserInfo.class);
        queryWrapperBuilder.matchStr(UserInfo::getLoginName, loginName, MatchTypeEnum.TERM, BooleanClause.Occur.MUST);
        List<UserInfo> list = this.indexHelper.search(queryWrapperBuilder.build());
        if (CollUtil.isEmpty(list)) {
            throw new AppException(JdfSystemMsgEnum.LOGIN_FAIL);
        }
        UserInfo userInfo = list.get(0);
        byte[] rawPassword = userInfo.getPassword().getBytes(StandardCharsets.UTF_8);
        HMac hMac = SecureUtil.hmacMd5(this.configInfoCache.getValue(ConfigCodeEnum.USER_MAC_SECRET.getCode()));
        String targetRaw = hMac.digestHex(password);
        if (!hMac.verify(targetRaw.getBytes(StandardCharsets.UTF_8), rawPassword)) {
            throw new AppException(JdfSystemMsgEnum.LOGIN_FAIL);
        }
        return userInfo;
    }

    /**
     * 查询
     *
     * @param userInfo userInfo
     * @return List
     */
    @Override
    public List<UserInfo> listInfoWithoutPage(UserInfo userInfo) {
        QueryWrapperBuilder<UserInfo> queryWrapperBuilder = this.buildQuery(userInfo);
        return this.indexHelper.search(queryWrapperBuilder.build());
    }

    /**
     * 详情
     *
     * @param id 主键
     * @return UserInfo
     */
    @Override
    public UserInfo detail(String id) {
        IdQueryWrapperBuilder<UserInfo> idQueryWrapperBuilder = new IdQueryWrapperBuilder<>(UserInfo.class, id);
        return this.indexHelper.searchById(idQueryWrapperBuilder.build());
    }

    /**
     * 保存
     *
     * @param userInfo userInfo
     */
    @Override
    public void saveInfo(UserInfo userInfo) {
        CountQueryWrapperBuilder<UserInfo> countQueryWrapperBuilder = new CountQueryWrapperBuilder<>(UserInfo.class);
        countQueryWrapperBuilder.matchStr(UserInfo::getLoginName, userInfo.getLoginName(), MatchTypeEnum.TERM, BooleanClause.Occur.MUST);
        Long count = this.indexHelper.count(countQueryWrapperBuilder.build());
        if(Objects.nonNull(count) && count > 0) {
            throw new AppException(MessageEnum.SYSTEM_FAIL.getCode(), "登录名已存在");
        }
        HMac hMac = SecureUtil.hmacMd5(this.configInfoCache.getValue(ConfigCodeEnum.USER_MAC_SECRET.getCode()));
        String rawPassword = hMac.digestHex(userInfo.getPassword());
        userInfo.setPassword(rawPassword);
        this.indexHelper.addDocument(userInfo);
    }

    /**
     * 更新
     *
     * @param userInfo userInfo
     */
    @Override
    public void updateInfo(UserInfo userInfo) {
        if (CharSequenceUtil.isNotEmpty(userInfo.getPassword())) {
            HMac hMac = SecureUtil.hmacMd5(this.configInfoCache.getValue(ConfigCodeEnum.USER_MAC_SECRET.getCode()));
            String rawPassword = hMac.digestHex(userInfo.getPassword());
            userInfo.setPassword(rawPassword);
        }
        this.indexHelper.updateDocumentById(userInfo);
    }

    /**
     * 删除
     *
     * @param ids 主键列表
     */
    @Override
    public void deleteInfo(List<String> ids) {
        if (CollUtil.isEmpty(ids)) {
            return;
        }
        DeleteByIdsWrapperBuilder<UserInfo> deleteByIdsWrapperBuilder = new DeleteByIdsWrapperBuilder<>(UserInfo.class, ids);
        this.indexHelper.deleteByIds(deleteByIdsWrapperBuilder.build());
    }

    /**
     * 初始化
     */
    @Override
    public void init() {
        QueryWrapperBuilder<UserInfo> queryWrapperBuilder = new QueryWrapperBuilder<>(UserInfo.class);
        List<UserInfo> list = this.indexHelper.search(queryWrapperBuilder.build());
        Set<String> loginNameSet = list.stream().map(UserInfo::getLoginName).collect(Collectors.toSet());
        String initStr = ResourceUtil.readUtf8Str("init/user_info.json");
        List<UserInfo> initList = FastJsonUtil.parseArray(initStr, UserInfo.class);
        HMac hMac = SecureUtil.hmacMd5(this.configInfoCache.getValue(ConfigCodeEnum.USER_MAC_SECRET.getCode()));
        initList.stream().filter(f -> !loginNameSet.contains(f.getLoginName())).forEach(f -> {
            f.setPassword(hMac.digestHex(f.getPassword()));
            f.setAttachInfo(CollUtil.newHashSet(StrConstant.NOT_SYNC));
            this.indexHelper.addDocument(f);
        });
        log.info("用户信息初始化完成");
    }

    private QueryWrapperBuilder<UserInfo> buildQuery(UserInfo userInfo) {
        QueryWrapperBuilder<UserInfo> queryWrapperBuilder = new QueryWrapperBuilder<>(UserInfo.class);
        if (CharSequenceUtil.isNotEmpty(userInfo.getUserName())) {
            queryWrapperBuilder.matchStr(UserInfo::getUserName, userInfo.getUserName(), MatchTypeEnum.TERM, BooleanClause.Occur.MUST);
        }
        if (CharSequenceUtil.isNotEmpty(userInfo.getLoginName())) {
            queryWrapperBuilder.matchStr(UserInfo::getLoginName, userInfo.getLoginName(), MatchTypeEnum.TERM, BooleanClause.Occur.MUST);
        }
        return queryWrapperBuilder;
    }
}
